# Sudoku Solver
# Tamara Roberson <tamara.roberson@gmail.com>
# Based on code from sfabriz.
# For detailed explanation, see:
#   http://www.osix.net/modules/article/?id=792

namespace SudokuSolver

import System
import System.Collections.Generic
import System.IO
import System.Text

import Mono.Unix

class Program:
	_ = Catalog.GetString
	_dim as int
	_sdlx as SudokuSolveDLX
	_data = List of string ()

	# Constructor
	def constructor (
	  [required] fname as string,
	  [required (dim >= 1)] dim as int):
		_dim = dim

		print _("Starting:")

		_data = ReadFile (fname)	
		
		// got the strings
		_sdlx = SudokuSolveDLX (_dim)
		_sdlx.GotSolutionEvent += PrintSolution
		_sdlx.BuildSudokuMatrix ()

		for num in range (0, _data.Count / _dim):
			SolvePuzzle (num)

		print _("Done")


	# Methods
	# Methods :: Private
	# Methods :: Private :: ReadFile
	private def ReadFile ([required] fname as string):
		for line in File.ReadAllLines (fname):
			line = line.Trim ()
			_data.Add (line) if (line != String.Empty)
					
		return _data 


	# Methods :: Private :: PrintOriginalGrid
	private def PrintOriginalGrid ([required] grid as (string)):
		print _("Original grid:")
		for cell in range (0, grid.Length):
			print grid[cell]


	# Methods :: Private :: PrintSolvedGrid
	private def PrintSolvedGrid ():
		print _("Solved grid:")
		_sdlx.SolveSudoku ()

		tot = _sdlx.TotSolutions
		print Catalog.GetPluralString (
		  "Found ${tot} solution", "Found ${tot} solutions", tot)


	# Methods :: Private :: SolvePuzzle
	private def SolvePuzzle ([required (num >= 0)] num as int):
		grid = array (string, _dim)

		for row in range (0, _dim):
			grid[row] = _data[num * _dim + row];
			
		print _("Solving sudoku # ${num}")
		print
		PrintOriginalGrid (grid)
		_sdlx.SetStartingGrid (grid)
		print
		PrintSolvedGrid ()
		print
		print


	# Handlers :: PrintSolution
	private def PrintSolution (sdlx as SudokuSolveDLX):
	"""<summary>Prints out the solution</summary>"""
		print _("Solution # ${sdlx.TotSolutions}")
		print
		
		solution = array (int, sdlx.Solutions.Count)
		index = 0

		for node as ZoeTools.Objects.LinkedMatrix.Node in sdlx.Solutions:
			solution[index] = node.Row
			index++

		Array.Sort (solution)

		for row in range (0, solution.Length):
			solution[row] = solution[row] % _dim

		for row in range (0, sdlx.Dim):
			for col in range (0, sdlx.Dim):
				n = solution[row * sdlx.Dim + col] + 1
				n_str = n.ToString ()
				n_str_pad = n_str.PadRight (2)
				Console.Write (n_str_pad)
			print
		print


### MAIN ###
def Main (args as (string)):
	fname as string
	try: fname = args[0]
	except: fname = "sudoku.txt"

	dim = 9

	Program (fname, dim)

